/*
 * Copyright (c) 2025 CAX Conversion Project
 */
package com.comac.ins.isfd.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.comac.ins.common.core.constant.CommonConstant;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.json.utils.JsonUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.constant.enums.IsfdMetadataTableNameEnum;
import com.comac.ins.isfd.domain.IsfdMetadataManagement;
import com.comac.ins.isfd.domain.IsfdMetadataManagementSheet;
import com.comac.ins.isfd.domain.bo.IsfdMetadataBusinessRefDatabaseBo;
import com.comac.ins.isfd.domain.bo.IsfdMetadataManagementBo;
import com.comac.ins.isfd.domain.vo.*;
import com.comac.ins.isfd.factory.IsfdMetadataImportFactory;
import com.comac.ins.isfd.mapper.IsfdMetadataManagementMapper;
import com.comac.ins.isfd.mapper.IsfdMetadataManagementSheetMapper;
import com.comac.ins.isfd.service.*;
import com.comac.ins.isfd.util.ExcelDataQualityCheckUtils;
import com.comac.ins.isfd.util.ExcelUtils;
import com.comac.ins.isfd.util.FileUtils;
import com.comac.ins.system.domain.vo.SysOssVo;
import com.comac.ins.system.service.ISysDictDataService;
import com.comac.ins.system.service.ISysOssService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;

/**
 * 元数据管理-数据管理Service业务层处理
 *
 * @author Lion Li
 * @date 2024-09-23
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class IsfdMetadataManagementServiceImpl implements IIsfdMetadataManagementService {

    @Autowired
    private IsfdMetadataManagementMapper baseMapper;

    @Autowired
    private IsfdMetadataManagementSheetMapper sheetMapper;

    @Autowired
    private IIsfdMetadataBusinessSceneDefinitionService iIsfdMetadataBusinessSceneDefinitionService;

    @Autowired
    private IIsfdMetadataBusinessRefDatabaseService iIsfdMetadataBusinessRefDatabaseService;

    @Autowired
    private IIsfdMetadataDatabaseService iIsfdMetadataDatabaseService;

    @Autowired
    private ISysDictDataService iSysDictDataService;

    @Autowired
    private IsfdMetadataImportFactory isfdMetadataImportFactory;

    @Autowired
    private ISysOssService iSysOssService;

    /**
     * 查询元数据管理-数据管理
     *
     * @param id 主键
     * @return 元数据管理-数据管理
     */
    @Override
    public IsfdMetadataManagementVo queryById(String id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询元数据管理-数据管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 元数据管理-数据管理分页列表
     */
    @Override
    public TableDataInfo<IsfdMetadataManagementVo> queryPageList(IsfdMetadataManagementBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<IsfdMetadataManagement> lqw = buildQueryWrapper(bo);
        Page<IsfdMetadataManagementVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的元数据管理-数据管理列表
     *
     * @param bo 查询条件
     * @return 元数据管理-数据管理列表
     */
    @Override
    public List<IsfdMetadataManagementVo> queryList(IsfdMetadataManagementBo bo) {
        LambdaQueryWrapper<IsfdMetadataManagement> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<IsfdMetadataManagement> buildQueryWrapper(IsfdMetadataManagementBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<IsfdMetadataManagement> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getBusinessId() != null, IsfdMetadataManagement::getBusinessId, bo.getBusinessId());
        lqw.eq(bo.getDatabaseId() != null, IsfdMetadataManagement::getDatabaseId, bo.getDatabaseId());
        lqw.like(StringUtils.isNotBlank(bo.getBusinessName()), IsfdMetadataManagement::getBusinessName, bo.getBusinessName());
        lqw.eq(StringUtils.isNotBlank(bo.getDataQualityId()), IsfdMetadataManagement::getDataQualityId, bo.getDataQualityId());
        lqw.eq(StringUtils.isNotBlank(bo.getDataQuality()), IsfdMetadataManagement::getDataQuality, bo.getDataQuality());
        lqw.eq(bo.getChildBusinessId() != null, IsfdMetadataManagement::getChildBusinessId, bo.getChildBusinessId());
        lqw.eq(StringUtils.isNotBlank(bo.getDatabaseType()), IsfdMetadataManagement::getDatabaseType, bo.getDatabaseType());
        lqw.eq(StringUtils.isNotBlank(bo.getDataOwnerId()), IsfdMetadataManagement::getDataOwnerId, bo.getDataOwnerId());
        lqw.like(StringUtils.isNotBlank(bo.getDataOwnerName()), IsfdMetadataManagement::getDataOwnerName, bo.getDataOwnerName());
        lqw.eq(StringUtils.isNotBlank(bo.getDataSafeLevel()), IsfdMetadataManagement::getDataSafeLevel, bo.getDataSafeLevel());
        lqw.eq(StringUtils.isNotBlank(bo.getDataRetentionPolicy()), IsfdMetadataManagement::getDataRetentionPolicy, bo.getDataRetentionPolicy());
        lqw.like(StringUtils.isNotBlank(bo.getFileName()), IsfdMetadataManagement::getFileName, bo.getFileName());
        lqw.eq(StringUtils.isNotBlank(bo.getFileType()), IsfdMetadataManagement::getFileType, bo.getFileType());
        lqw.eq(StringUtils.isNotBlank(bo.getFileUrl()), IsfdMetadataManagement::getFileUrl, bo.getFileUrl());
        lqw.eq(bo.getInventoryCount() != null, IsfdMetadataManagement::getInventoryCount, bo.getInventoryCount());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            IsfdMetadataManagement::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        return lqw;
    }


    @Override
    public String getDataPreview(IsfdMetadataManagementBo bo) {
        IsfdMetadataManagementVo vo = baseMapper.selectVoById(bo.getId());
        return vo.getFileUrl();
    }

    @Override
    public String getDataMapping(IsfdMetadataManagementBo bo) {
        String metadataManagementId = bo.getId();
        LambdaQueryWrapper<IsfdMetadataManagementSheet> lqw = new LambdaQueryWrapper<IsfdMetadataManagementSheet>().eq(IsfdMetadataManagementSheet::getMetadataManagementId, metadataManagementId);
        IsfdMetadataManagementSheetVo sheetVo = sheetMapper.selectVoOne(lqw);
        return sheetVo.getMapFields();
    }

    @Override
    public Map<String, Object> assessExcelQuality(MultipartFile multipartFile, String timeCheckString, String outlierCheckString) {
        String jsonString = ExcelDataQualityCheckUtils.excelDataQualityCheck(multipartFile, timeCheckString, outlierCheckString);
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> resultMap = null;
        try {
            // 将字符串转为Map
            resultMap = objectMapper.readValue(jsonString, Map.class);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
        }
        return resultMap;
    }


    @Override
    public List<IsfdMetadataManagementTableInfoVo> tableInfo(Long businessId, Long databaseId, String tableName) {
        List<IsfdMetadataManagementTableInfoVo> result = new ArrayList<>();

        // 如果是直接查询某个表
        if (StringUtils.isNotBlank(tableName)) {
            IsfdMetadataManagementTableInfoVo isfdMetadataManagementTableInfoVo = new IsfdMetadataManagementTableInfoVo();
            String tableFieldsJsonArrayStr = iSysDictDataService.selectDictValueByTypeAndLabel(CommonConstant.METADATA_CONFIG, tableName);
            isfdMetadataManagementTableInfoVo.setTableName(tableName);
            isfdMetadataManagementTableInfoVo.setMapFiledsList(JsonUtils.parseArray(tableFieldsJsonArrayStr, MapFieldsVo.class));
            result.add(isfdMetadataManagementTableInfoVo);
            return result;
        }

        // 如果根据业务id和数据库id查询
        IsfdMetadataBusinessRefDatabaseBo isfdMetadataBusinessRefDatabaseBo = new IsfdMetadataBusinessRefDatabaseBo();
        isfdMetadataBusinessRefDatabaseBo.setBusinessId(businessId);
        isfdMetadataBusinessRefDatabaseBo.setDatabaseId(databaseId);
        isfdMetadataBusinessRefDatabaseBo.setIsDeleted(0L);
        List<IsfdMetadataBusinessRefDatabaseVo> isfdMetadataBusinessRefDatabaseVoList = iIsfdMetadataBusinessRefDatabaseService.queryList(isfdMetadataBusinessRefDatabaseBo);
        if (CollectionUtils.isEmpty(isfdMetadataBusinessRefDatabaseVoList)) {
            throw new BaseException("业务没有关联相关数据库，请确认后重试！");
        }
        IsfdMetadataDatabaseVo isfdMetadataDatabaseVo = iIsfdMetadataDatabaseService.queryById(databaseId);
        if (isfdMetadataDatabaseVo == null) {
            throw new BaseException("要素数据库不存在，请确认后重试！");
        }
        String[] tableNames = isfdMetadataDatabaseVo.getStorageLocation().split(",");
        for (String t : tableNames) {
            IsfdMetadataManagementTableInfoVo isfdMetadataManagementTableInfoVo = new IsfdMetadataManagementTableInfoVo();
            String tableFieldsJsonArrayStr = iSysDictDataService.selectDictValueByTypeAndLabel(CommonConstant.METADATA_CONFIG, t);
            isfdMetadataManagementTableInfoVo.setTableName(t);
            isfdMetadataManagementTableInfoVo.setMapFiledsList(JsonUtils.parseArray(tableFieldsJsonArrayStr, MapFieldsVo.class));
            result.add(isfdMetadataManagementTableInfoVo);
        }
        return result;
    }

    /**
     * 确认导入
     */
    @Override
    public Long save(MultipartFile multipartFile, IsfdMetadataManagementBo bo) {
        // 1. 校验
        IsfdMetadataBusinessRefDatabaseBo isfdMetadataBusinessRefDatabaseBo = new IsfdMetadataBusinessRefDatabaseBo();
        isfdMetadataBusinessRefDatabaseBo.setBusinessId(bo.getBusinessId());
        isfdMetadataBusinessRefDatabaseBo.setDatabaseId(bo.getDatabaseId());
        isfdMetadataBusinessRefDatabaseBo.setIsDeleted(0L);
        List<IsfdMetadataBusinessRefDatabaseVo> isfdMetadataBusinessRefDatabaseVoList = iIsfdMetadataBusinessRefDatabaseService.queryList(isfdMetadataBusinessRefDatabaseBo);
        if (CollectionUtils.isEmpty(isfdMetadataBusinessRefDatabaseVoList)) {
            throw new BaseException("业务没有关联相关数据库，请确认后重试！");
        }

        IsfdMetadataBusinessSceneDefinitionVo isfdMetadataBusinessSceneDefinitionVo = iIsfdMetadataBusinessSceneDefinitionService.queryById(bo.getBusinessId());
        if (isfdMetadataBusinessSceneDefinitionVo == null) {
            throw new BaseException("业务场景不存在，请确认后重试！");
        }

        IsfdMetadataDatabaseVo isfdMetadataDatabaseVo = iIsfdMetadataDatabaseService.queryById(bo.getDatabaseId());
        if (isfdMetadataDatabaseVo == null) {
            throw new BaseException("要素数据库不存在，请确认后重试！");
        }

        // 2. 根据 mapFields 处理excel文件，替换表头，分出sheet
        String dir = iSysDictDataService.selectDictValueByTypeAndLabel(CommonConstant.METADATA_CONSTANTS, CommonConstant.METADATA_EXCEL_PREFIX);
        if (StringUtils.isBlank(dir)) {
            throw new BaseException("excel目录字典未配置，请确认后重试！");
        }
        String mapFields = bo.getMapFields();
        JSONObject mapFieldsJson = JSONUtil.parseObj(mapFields);
        Set<String> keys = mapFieldsJson.keySet();
        Map<String, File> sheetMap = null;
        Boolean isManySheet = Boolean.FALSE;
        if (CollectionUtils.isNotEmpty(keys) && keys.size() > 1) {
            sheetMap = ExcelUtils.splitExcelBySheet(multipartFile, mapFields);
            isManySheet = Boolean.TRUE;
        }
        sheetMap = ExcelUtils.splitExcelBySheet(multipartFile, mapFields);

        // 生成uuid,作为managementId
        String id = IdUtil.fastSimpleUUID();
        String finalDir = dir + id;

        long resultCount = 0L;
        File excelFile = null;
        try {
            // 多sheet和单sheet的处理方式不同
            if (isManySheet) {
                // 3. 根据表名选择工厂模式
                for (String sheetAndTableName : sheetMap.keySet()) {
                    String[] sheetAndTableNames = sheetAndTableName.split("::");
                    String sheetName = sheetAndTableNames[0];
                    String tableName = sheetAndTableNames[1];
                    File sheetExcelFile = sheetMap.get(sheetAndTableName);

                    // 工厂选择实现类
                    IsfdMetadataTableNameEnum isfdMetadataTableNameEnum = IsfdMetadataTableNameEnum.forValue(tableName);
                    IIsfdMetadataImportService iIsfdMetadataImportService = isfdMetadataImportFactory.getMetadataImportServiceByTableName(isfdMetadataTableNameEnum);
                    Long successCount = iIsfdMetadataImportService.excelImport(sheetExcelFile, id);

                    // 4.上传文件到minio
                    SysOssVo sheetUploadVo = iSysOssService.upload(sheetExcelFile, finalDir);
                    // 5.落表sheet
                    String sheetId = IdUtil.fastSimpleUUID();
                    IsfdMetadataManagementSheet sheetPo = new IsfdMetadataManagementSheet();
                    sheetPo.setId(sheetId);
                    sheetPo.setMetadataManagementId(id);
                    sheetPo.setTableName(tableName);
                    Map<String, List<MapFieldsVo>> sheetMapFields = new HashMap<>();
                    sheetMapFields.put(sheetAndTableName, JsonUtils.parseArray(mapFieldsJson.getStr(sheetAndTableName), MapFieldsVo.class));
                    sheetPo.setMapFields(JsonUtils.toJsonString(sheetMapFields));
                    sheetPo.setSheetName(sheetName);
                    sheetPo.setSheetUrl(sheetUploadVo.getUrl());
                    sheetPo.setInventoryCount(successCount);
                    sheetMapper.insert(sheetPo);
                    // 6.统计成功给数据
                    resultCount = resultCount + successCount;
                }

                // 7. 上传文件到file到minio，落表management
                SysOssVo uploadVo = iSysOssService.upload(multipartFile, finalDir);
                IsfdMetadataManagement po = MapstructUtils.convert(bo, IsfdMetadataManagement.class);
                po.setId(id);
                po.setBusinessName(isfdMetadataBusinessSceneDefinitionVo.getName());
                po.setDatabaseType(isfdMetadataDatabaseVo.getDatabaseType());
                po.setFileUrl(uploadVo.getUrl());
                po.setFileName(uploadVo.getOriginalName());
                po.setFileType(uploadVo.getFileSuffix());
                po.setInventoryCount(resultCount);
                baseMapper.insert(po);
            } else {
                // 3.先上传
                SysOssVo uploadVo = iSysOssService.upload(multipartFile, finalDir);
                String sheetAndTableName = keys.iterator().next();
                String[] sheetAndTableNames = sheetAndTableName.split("::");
                String tableName = sheetAndTableNames[1];

                // 4.工厂选择实现类
//                excelFile = FileUtils.multiPartFileToFile(multipartFile);
                excelFile = sheetMap.get(sheetAndTableName);
                IsfdMetadataTableNameEnum isfdMetadataTableNameEnum = IsfdMetadataTableNameEnum.forValue(tableName);
                IIsfdMetadataImportService iIsfdMetadataImportService = isfdMetadataImportFactory.getMetadataImportServiceByTableName(isfdMetadataTableNameEnum);
                Long successCount = iIsfdMetadataImportService.excelImport(excelFile, id);

                // 5.落表sheet
                String sheetId = IdUtil.fastSimpleUUID();
                IsfdMetadataManagementSheet sheetPo = new IsfdMetadataManagementSheet();
                sheetPo.setId(sheetId);
                sheetPo.setMetadataManagementId(id);
                sheetPo.setTableName(tableName);
                sheetPo.setMapFields(bo.getMapFields());
                sheetPo.setSheetName(uploadVo.getOriginalName());
                sheetPo.setSheetUrl(uploadVo.getUrl());
                sheetPo.setInventoryCount(successCount);
                sheetMapper.insert(sheetPo);

                // 6.落表management
                IsfdMetadataManagement po = MapstructUtils.convert(bo, IsfdMetadataManagement.class);
                po.setId(id);
                po.setBusinessName(isfdMetadataBusinessSceneDefinitionVo.getName());
                po.setDatabaseType(isfdMetadataDatabaseVo.getDatabaseType());
                po.setFileUrl(uploadVo.getUrl());
                po.setFileName(uploadVo.getOriginalName());
                po.setFileType(uploadVo.getFileSuffix());
                po.setInventoryCount(successCount);
                baseMapper.insert(po);
                resultCount = successCount;
            }
        } catch (Exception e) {
            log.error("导入数据失败", e);
            throw new BaseException("导入数据失败，请确认后重试！");
        } finally {
            // 8.删除临时文件
            if (CollectionUtils.isNotEmpty(sheetMap)) {
                for (String key : sheetMap.keySet()) {
                    File file = sheetMap.get(key);
                    if (file != null && file.exists()) {
                        file.delete();
                    }
                }
            }
            if (excelFile != null && excelFile.exists()) {
                excelFile.delete();
            }
        }
        return resultCount;
    }
}
